package com.gobang.service.impl;

import com.gobang.common.exception.ErrorCode;
import com.gobang.common.exception.MatchException;
import com.gobang.common.util.MatchUtils;
import com.gobang.domain.entity.MatchQueueEntry;
import com.gobang.domain.entity.User;
import com.gobang.domain.vo.MatchResponseVO;
import com.gobang.domain.vo.UserInfoVO;
import com.gobang.service.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

/**
 * 匹配系统业务服务实现类（替换Mock实现）
 * 实现匹配系统的核心业务逻辑
 *
 * @author gobang-team
 * @since 1.0.0
 */
@Service
// @Primary // 优先使用此实现，替换Mock实现
@RequiredArgsConstructor
@Slf4j
@Transactional
public class MatchServiceImpl implements MatchService {

    private final UserService userService;
    private final QueueManager queueManager;
    private final MessageService messageService;
    private final ConnectionManagerService connectionManagerService;
    private final MatchAlgorithm matchAlgorithm;
    private final GameRoomService gameRoomService;

    /**
     * 用户加入匹配队列
     */
    @Override
    public MatchResponseVO joinMatchQueue(Long userId) {
        log.info("处理用户{}加入匹配队列请求", userId);
        
        try {
            // 1. 验证用户状态
            validateUserStatus(userId);
            
            // 2. 获取用户积分信息
            UserInfoVO user = userService.getUserById(userId);
            if (user == null) {
                log.error("用户{}不存在", userId);
                throw new MatchException(ErrorCode.USER_NOT_FOUND);
            }
            
            // 3. 检查是否已在队列中
            if (queueManager.isInQueue(userId)) {
                log.warn("用户{}已在匹配队列中", userId);
                throw MatchException.alreadyInQueue();
            }
            
            // 4. 加入匹配队列
            int queuePosition = queueManager.addToQueue(userId, user.getCurrentScore());
            
            // 5. 更新用户状态
            connectionManagerService.updateUserStatus(userId, "matching");
            
            // 6. 计算预估等待时间
            long estimatedWaitTime = MatchUtils.calculateEstimatedWaitTime(queuePosition);
            int queueSize = queueManager.getQueueSize();
            
            // 7. 推送匹配状态更新
            var statusMsg = MatchUtils.createMatchStatusUpdateMessage(
                    "MATCHING", (int) estimatedWaitTime, queuePosition);
            messageService.sendMatchStatusUpdate(userId, statusMsg);
            
            // 8. 返回响应
            MatchResponseVO response = MatchResponseVO.builder()
                    .success(true)
                    .queuePosition(queuePosition)
                    .estimatedWaitTime(estimatedWaitTime)
                    .queueSize(queueSize)
                    .statusMessage(MatchUtils.generateStatusMessage("MATCHING", queuePosition, (int) estimatedWaitTime))
                    .build();
            
            log.info("用户{}成功加入匹配队列，位置：{}，预估等待时间：{}秒", userId, queuePosition, estimatedWaitTime);
            return response;
            
        } catch (MatchException e) {
            log.error("用户{}加入匹配队列失败", userId, e);
            throw MatchException.joinQueueFailed();
        } catch (Exception e) {
            log.error("用户{}加入匹配队列失败", userId, e);
            throw e;
        }
    }

    /**
     * 用户取消匹配
     */
    @Override
    public boolean cancelMatch(Long userId) {
        log.info("处理用户{}取消匹配请求", userId);
        
        try {
            // 1. 检查是否在队列中
            if (!queueManager.isInQueue(userId)) {
                log.warn("用户{}不在匹配队列中", userId);
                throw MatchException.notInQueue();
            }
            
            // 2. 从队列中移除
            boolean removed = queueManager.removeFromQueue(userId);
            
            if (removed) {
                // 3. 更新用户状态
                connectionManagerService.updateUserStatus(userId, "online");
                
                // 4. 推送状态更新
                var statusMsg = MatchUtils.createMatchStatusUpdateMessage("ONLINE", 0, 0);
                messageService.sendMatchStatusUpdate(userId, statusMsg);
                
                log.info("用户{}成功取消匹配", userId);
                return true;
            } else {
                log.error("用户{}取消匹配失败", userId);
                throw MatchException.cancelFailed();
            }
            
        } catch (MatchException e) {
            log.error("用户{}取消匹配异常", userId, e);
            throw MatchException.cancelFailed();
        } catch (Exception e) {
            log.error("用户{}取消匹配异常", userId, e);
            throw e;
        }
    }


    /**
     * 验证用户状态
     */
    private void validateUserStatus(Long userId) {
        // 检查用户是否在线
        if (!connectionManagerService.isUserOnline(userId)) {
            log.error("用户{}不在线", userId);
            throw new MatchException(ErrorCode.USER_NOT_LOGIN);
        }
        
        // 检查用户状态是否允许匹配
        String userStatus = connectionManagerService.getUserStatus(userId);
        if ("gaming".equals(userStatus)) {
            log.error("用户{}正在游戏中，不能加入匹配", userId);
            throw MatchException.userStatusError();
        }
    }

    /**
     * 手动触发匹配（用于测试和管理）
     */
    @Override
    public void triggerMatch() {
        log.info("手动触发匹配算法");
        
        try {
            List<MatchQueueEntry> waitingUsers = queueManager.getWaitingUsers();
            
            if (waitingUsers.size() < 2) {
                log.info("等待队列用户数量不足：{}", waitingUsers.size());
                return;
            }
            
            List<MatchAlgorithm.MatchPair> matchPairs = matchAlgorithm.batchMatch(waitingUsers);
            
            if (matchPairs.isEmpty()) {
                log.info("未找到合适的匹配对");
                return;
            }
            
            log.info("手动匹配成功，配对数：{}", matchPairs.size());
            
            for (MatchAlgorithm.MatchPair pair : matchPairs) {
                handleMatchSuccess(pair);
            }
            
        } catch (Exception e) {
            log.error("手动触发匹配异常", e);
        }
    }

    /**
     * 处理匹配成功
     */
    private void handleMatchSuccess(MatchAlgorithm.MatchPair pair) {
        MatchQueueEntry user1 = pair.getUser1();
        MatchQueueEntry user2 = pair.getUser2();
        
        try {
            log.info("处理匹配成功：用户{}({}) vs 用户{}({})", 
                    user1.getUserId(), user1.getCurrentScore(),
                    user2.getUserId(), user2.getCurrentScore());

            // 随机分配黑白方
            String user1Color = MatchUtils.randomPlayerColor();
            String user2Color = MatchUtils.getOpponentColor(user1Color);

            // 创建游戏房间
            GameRoomService.RoomCreationResult roomResult = gameRoomService.createRoom(
                    "BLACK".equals(user1Color) ? user1.getUserId() : user2.getUserId(),
                    "WHITE".equals(user1Color) ? user1.getUserId() : user2.getUserId()
            );

            if (!roomResult.isSuccess()) {
                log.error("游戏房间创建失败：{}", roomResult.getErrorMessage());
                handleRoomCreationFailure(user1.getUserId(), user2.getUserId());
                return;
            }

            String roomId = roomResult.getRoomId();
            String startTime = LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);

            // 从队列中移除已匹配的用户
            queueManager.removeFromQueue(user1.getUserId());
            queueManager.removeFromQueue(user2.getUserId());

            // 更新用户状态为游戏中
            connectionManagerService.updateUserStatus(user1.getUserId(), "gaming");
            connectionManagerService.updateUserStatus(user2.getUserId(), "gaming");

            // 将用户加入房间
            connectionManagerService.addUserToRoom(roomId, user1.getUserId());
            connectionManagerService.addUserToRoom(roomId, user2.getUserId());

            // 推送匹配成功通知
            notifyMatchSuccess(user1, user2, roomId, user1Color, user2Color, startTime);

            log.info("匹配成功处理完成：房间{}，用户{}({}) vs 用户{}({})", 
                    roomId, user1.getUserId(), user1Color, user2.getUserId(), user2Color);

        } catch (Exception e) {
            log.error("处理匹配成功异常：用户{} vs 用户{}", user1.getUserId(), user2.getUserId(), e);
            handleMatchFailure(user1.getUserId(), user2.getUserId());
        }
    }

    /**
     * 通知匹配成功
     */
    private void notifyMatchSuccess(MatchQueueEntry user1, MatchQueueEntry user2, 
                                   String roomId, String user1Color, String user2Color, String startTime) {
        try {
            // 构造对手信息
            MatchOpponentInfo opponent1 = new MatchOpponentInfo(
                    user2.getUserId(), user2.getUsername(), user2.getCurrentScore());
            MatchOpponentInfo opponent2 = new MatchOpponentInfo(
                    user1.getUserId(), user1.getUsername(), user1.getCurrentScore());

            // 为用户1推送匹配成功消息
            var successMsg1 = MatchUtils.createMatchSuccessMessage(roomId, opponent1, user1Color, startTime);
            messageService.sendMatchSuccessNotification(user1.getUserId(), successMsg1);

            // 为用户2推送匹配成功消息
            var successMsg2 = MatchUtils.createMatchSuccessMessage(roomId, opponent2, user2Color, startTime);
            messageService.sendMatchSuccessNotification(user2.getUserId(), successMsg2);

        } catch (Exception e) {
            log.error("通知匹配成功异常：用户{} vs 用户{}", user1.getUserId(), user2.getUserId(), e);
        }
    }

    /**
     * 处理房间创建失败
     */
    private void handleRoomCreationFailure(Long userId1, Long userId2) {
        try {
            log.warn("房间创建失败，恢复用户状态：{}, {}", userId1, userId2);

            // 恢复用户在线状态
            connectionManagerService.updateUserStatus(userId1, "online");
            connectionManagerService.updateUserStatus(userId2, "online");

            // 发送错误通知
            messageService.sendErrorResponse(userId1, ErrorCode.MATCH_ROOM_CREATE_FAILED, "匹配成功但房间创建失败");
            messageService.sendErrorResponse(userId2, ErrorCode.MATCH_ROOM_CREATE_FAILED, "匹配成功但房间创建失败");

        } catch (Exception e) {
            log.error("处理房间创建失败异常", e);
        }
    }

    /**
     * 处理匹配失败
     */
    private void handleMatchFailure(Long userId1, Long userId2) {
        try {
            log.warn("匹配处理失败，恢复用户状态：{}, {}", userId1, userId2);

            // 确保用户状态正确
            connectionManagerService.updateUserStatus(userId1, "matching");
            connectionManagerService.updateUserStatus(userId2, "matching");

        } catch (Exception e) {
            log.error("处理匹配失败异常", e);
        }
    }

    /**
     * 获取匹配系统状态
     */
    @Override
    public MatchSystemStatus getMatchSystemStatus() {
        try {
            var queueStats = queueManager.getQueueStatistics();
            return new MatchSystemStatus(
                    true, // 系统运行状态
                    queueStats.getTotalUsers(),
                    queueStats.getAvgWaitTime(),
                    queueStats.getAvgScore(),
                    LocalDateTime.now()
            );
        } catch (Exception e) {
            log.error("获取匹配系统状态异常", e);
            return new MatchSystemStatus(false, 0, 0, 0, LocalDateTime.now());
        }
    }

} 